home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
minix
/
up1510b.tgz
/
up1510b
/
src
/
commands
/
expr.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-23
|
13KB
|
630 lines
/* expr - expression evaluator for shell Author: Peter S. Housel */
#include <string.h>
#include <ctype.h>
#include <stdio.h>
extern char *malloc( /* size_t nbytes */ );
struct value {
long numval; /* numeric value */
int nf_valid; /* "numeric value field valid" flag */
char *strval; /* string value */
};
#define numresult(valp,number) \
(((valp)->nf_valid = 1), \
((valp)->strval = NULL), \
((valp)->numval = (number)))
void invalid( /* char *err */ );
char *strvalue( /* struct value *valp */ );
int numvalue( /* struct value *valp */ );
char *strsave( /* char *string */ );
void expr1( /* struct value *valp */ ),
expr2( /* struct value *valp */ ),
expr3( /* struct value *valp */ ),
expr4( /* struct value *valp */ ),
expr5( /* struct value *valp */ ),
expr6( /* struct value *valp */ ),
expr7( /* struct value *valp */ );
void docolon( /* value *match, *pattern */ );
char *progname;
char **argp;
char NUMARG[] = "numeric argument required";
main(argc, argv)
int argc;
char *argv[];
{
struct value val0;
progname = argv[0];
argp = &argv[1];
expr1(&val0);
if (*argp != NULL) invalid("syntax error");
(void) puts(strvalue(&val0));
exit(nullz(&val0));
}
/* Yet Another recursive descent parser. */
void expr1(valp)
struct value *valp;
{
struct value val1;
expr2(valp);
while (*argp != NULL) {
if (strcmp(*argp, "|") == 0) {
++argp;
expr2(&val1);
if (nullz(valp))
*valp = val1;
else; /* return the first arg (already in *valp) */
} else
break;
}
}
void expr2(valp)
struct value *valp;
{
struct value val1;
expr3(valp);
while (*argp != NULL) {
if (strcmp(*argp, "&") == 0) {
++argp;
expr3(&val1);
if (nullz(valp) && nullz(&val1))
numresult(valp, 0);
else; /* return the first arg (already in *valp) */
} else
break;
}
}
/* Save source code lines but not object code, unfortunately. */
#define RELOP(OP) \
++argp; \
expr4(&val1); \
if(numvalue(valp) && numvalue(&val1)) \
numresult(valp, valp->numval OP val1.numval); \
else \
numresult(valp, strcmp(strvalue(valp), strvalue(&val1)) OP 0);
void expr3(valp)
struct value *valp;
{
struct value val1;
expr4(valp);
while (*argp != NULL) {
if (strcmp(*argp, "<") == 0) {
RELOP(<)
} else if (strcmp(*argp, "<=") == 0) {
RELOP(<=)
} else if (strcmp(*argp, "=") == 0) {
RELOP(==)
} else if (strcmp(*argp, "!=") == 0) {
RELOP(!=)
} else if (strcmp(*argp, ">=") == 0) {
RELOP(>=)
} else if (strcmp(*argp, ">") == 0) {
RELOP(>)
} else
break;
}
}
#define BINOP(NEXT,OP) \
++argp; \
NEXT(&val1); \
if(!numvalue(valp) || !numvalue(&val1)) \
invalid(NUMARG); \
else \
numresult(valp, valp->numval OP val1.numval); \
void expr4(valp)
struct value *valp;
{
struct value val1;
expr5(valp);
while (*argp != NULL) {
if (strcmp(*argp, "+") == 0) {
BINOP(expr5, +)
} else if (strcmp(*argp, "-") == 0) {
BINOP(expr5, -)
} else
break;
}
}
void expr5(valp)
struct value *valp;
{
struct value val1;
expr6(valp);
while (*argp != NULL) {
if (strcmp(*argp, "*") == 0) {
BINOP(expr6, *)
} else if (strcmp(*argp, "/") == 0) {
++argp;
expr6(&val1);
if (!numvalue(valp) || !numvalue(&val1))
invalid(NUMARG);
else {
if (val1.numval == 0) invalid("division by zero");
numresult(valp, valp->numval / val1.numval);
}
} else if (strcmp(*argp, "%") == 0) {
++argp;
expr6(&val1);
if (!numvalue(valp) || !numvalue(&val1))
invalid(NUMARG);
else {
if (val1.numval == 0) invalid("division by zero");
numresult(valp, valp->numval % val1.numval);
}
} else
break;
}
}
void expr6(valp)
struct value *valp;
{
struct value val1;
expr7(valp);
while (*argp != NULL) {
if (strcmp(*argp, ":") == 0) {
++argp;
expr7(&val1);
#ifndef NOCOLON
docolon(valp, &val1);
#else
valp->nf_valid = 0;
valp->strval = NULL;
#endif
} else
break;
}
}
void expr7(valp)
struct value *valp;
{
if (*argp == NULL)
invalid("missing argument(s)");
else if (strcmp(*argp, "(") == 0) {
++argp;
expr1(valp);
if (strcmp(*argp++, ")") != 0) invalid("unbalanced parentheses");
} else {
valp->nf_valid = 0;
valp->strval = *argp++;
}
}
/* Return 1 if the argument is zero (numeric) or null (string */
int nullz(valp)
struct value *valp;
{
if (numvalue(valp)) return(valp->numval == 0);
return(strlen(strvalue(valp)) == 0);
}
/* Return 1 if the argument is a valid number, insuring that the nf_valid
* and numval fields are set properly. Does the string-to-number
* conversion if nf_valid is false.
*/
int numvalue(valp)
struct value *valp;
{
register char *p;
int sign = 0, digits = 0;
unsigned long num = 0;
if (valp->nf_valid) return 1;
if ((p = valp->strval) == NULL) return 0;
if (*p == '-') {
++p;
sign = 1;
}
while (isdigit(*p)) {
num = num * 10 + (*p++ - '0');
digits = 1;
}
if (!digits || *p != '\0') return 0;
valp->numval = sign ? -num : num;
valp->nf_valid = 1;
return 1;
}
/* Return the string value of the given argument. If there is only a
* numeric value, convert it to a string
*/
char *strvalue(valp)
struct value *valp;
{
char numbuf[30];
register char *p;
unsigned long num;
int sign = 0;
if (!valp->nf_valid) return(valp->strval != NULL) ? valp->strval : "";
p = numbuf + sizeof numbuf;
*--p = '\0';
if (valp->numval < 0) {
num = -(valp->numval);
sign = 1;
} else
num = valp->numval;
do {
*--p = '0' + (num % 10);
num /= 10;
} while (num);
if (sign) *--p = '-';
return(valp->strval = strsave(p));
}
/* Save the given string in its own allocated memory and return a pointer
* to that memory.
*/
char *strsave(string)
char *string;
{
char *p;
if ((p = malloc(strlen(string) + 1)) == NULL) invalid("out of memory");
(void) strcpy(p, string);
return p;
}
/* Print error message and exit. */
void invalid(err)
char *err;
{
(void) fputs(progname, stderr);
(void) fputs(": ", stderr);
(void) fputs(err, stderr);
(void) putc('\n', stderr);
exit(2);
}
#ifndef NOCOLON
#include <limits.h>
#define RMIN (UCHAR_MAX-8) /* >= reserved as opcodes */
#define RESC (UCHAR_MAX-8) /* for escaping opcodes */
#define RDOT (UCHAR_MAX-7) /* match any character */
#define ROPEN (UCHAR_MAX-6) /* opening \( */
#define RCLOSE (UCHAR_MAX-5) /* closing \) */
#define RSTAR (UCHAR_MAX-4) /* Kleene closure */
#define RCLASS (UCHAR_MAX-3) /* character class */
#define RBACK (UCHAR_MAX-2) /* \digit reference */
#define REND (UCHAR_MAX-1) /* end of program */
#define RABEGIN 0x01 /* match anchored at BOL (^) */
#define RAEND 0x02 /* match anchored at EOL ($) */
#define RSELECT 0x04 /* \(...\) selection op used */
#define PROGLENGTH 1024 /* bytes reserved for r-programs */
#define CLASS_BYTES ((CHAR_MAX - CHAR_MIN) / CHAR_BIT)
unsigned char rprogram[PROGLENGTH]; /* regexp program storage */
unsigned int rflags = RABEGIN; /* regexp program context */
char *rbegins[10]; /* pointers to \( beginnings */
char *rends[10]; /* pointers to \) endings */
int rlevel; /* \(...\) level */
void rcomp( /* char *regexp */ );
void rmatch( /* char *str */ );
char *rtry( /* char *str, unsigned char **pcp */ );
char *tryone( /* char *str, unsigned char **pcp */ );
/* Compile the regexp, match it against the string, and return the
* proper result (a string if \(...\) used, and the match length otherwise.
*/
void docolon(match, pattern)
struct value *match, *pattern;
{
rcomp(strvalue(pattern));
rmatch(strvalue(match));
if (rflags & RSELECT) {
match->nf_valid = 0;
if (rends[0] == rbegins[0] || rends[1] == NULL) {
match->strval = NULL;
} else {
*(rends[1]) = '\0'; /* semi-nasty */
match->strval = rbegins[1];
}
} else {
numresult(match, rends[0] - rbegins[0]);
}
}
/* Compile an ed(1)-syntax regular-expression into the rprogram[] array. */
void rcomp(regexp)
register char *regexp;
{
char c; /* current regexp character */
char first, last; /* limits of character class */
unsigned char *starable; /* last "starable" variable */
unsigned char *rpc; /* pointer to next program sto